package com.stars.easyms.logging.log4j2.xml;

import com.stars.easyms.base.util.ReflectUtil;
import com.stars.easyms.logging.appender.EasyMsPlumeLogAppender;
import com.stars.easyms.logging.log4j2.layout.EasyMsLog4j2PatternLayout;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.*;
import org.apache.logging.log4j.core.config.plugins.util.PluginType;
import org.apache.logging.log4j.core.config.xml.XmlConfiguration;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

import static com.stars.easyms.logging.constant.EasyMsLoggingConstants.*;

/**
 * <p>className: EasyMsLog4j2XmlConfiguration</p>
 * <p>description: EasyMs的log4j2的xml配置类</p>
 *
 * @author guoguifang
 * @version 1.7.0
 * @date 2020/11/16 2:57 下午
 */
@SuppressWarnings("unchecked")
public class EasyMsLog4j2XmlConfiguration extends XmlConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(EasyMsLog4j2XmlConfiguration.class);

    public EasyMsLog4j2XmlConfiguration(LoggerContext loggerContext, ConfigurationSource configSource) {
        super(loggerContext, configSource);
    }

    @Override
    public void createConfiguration(final Node node, final LogEvent event) {
        // 先自定义各个节点的配置
        this.configNode(node);

        // 创建父类的配置信息
        super.createConfiguration(node, event);

        if (ELEMENTS_NAME_APPENDERS.equalsIgnoreCase(node.getName())) {
            final Object pluginObject = node.getObject();
            if (pluginObject instanceof Map) {
                Map map = (Map) pluginObject;
                map.put(EASY_MS_PLUME_LOG_APPENDER_NAME, new EasyMsPlumeLogAppender(EASY_MS_PLUME_LOG_APPENDER_NAME));
                node.setObject(map);
            }
        } else if (ELEMENTS_NAME_ROOT.equalsIgnoreCase(node.getName())) {
            final LoggerConfig loggerConfig = node.getObject();
            if (loggerConfig != null) {
                List<AppenderRef> appenderRefs = new ArrayList<>(loggerConfig.getAppenderRefs());
                appenderRefs.add(getAppenderRef());
                try {
                    ReflectUtil.writeField(loggerConfig, "appenderRefs", Collections.unmodifiableList(appenderRefs));
                } catch (Exception e) {
                    // ignore
                }
            }
        }
    }

    private void configNode(final Node node) {
        final PluginType<?> type = node.getType();
        Class<?> pluginClass = type.getPluginClass();
        if (PatternLayout.class.isAssignableFrom(pluginClass)) {
            try {
                ReflectUtil.writeFinalField(type, "pluginClass", EasyMsLog4j2PatternLayout.class);
            } catch (Exception e) {
                logger.error("Log4j2 class '{}' field pluginClass set value failure!", PluginType.class.getName(), e);
            }
        }
    }

    private AppenderRef getAppenderRef() {
        try {
            return ReflectUtil.getInstance(AppenderRef.class,
                    new Class<?>[]{String.class, Level.class, Filter.class},
                    new Object[]{EASY_MS_PLUME_LOG_APPENDER_NAME, null, null});
        } catch (Exception e) {
            logger.error("Get class '{}' instance failure!", AppenderRef.class.getName(), e);
        }
        return null;
    }
}
